<template>
  <el-dialog :visible="visible" title="图片导出" width="488px" append-to-body @open="onOpen" @close="onClose">
    <div>
      <el-form label-width="84px">
        <el-form-item label="导出样式" class="mb-4">
          <el-radio-group v-model="form.mimetype">
            <el-radio label="image/jpeg">JPG</el-radio>
            <el-radio label="image/png">PNG</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="导出页面" :class="{ 'mb-10': !form.mode }">
          <el-radio-group v-model="form.mode" @change="onChangeMode">
            <el-radio :label="0">部分页面</el-radio>
            <el-radio :label="1">全部页面</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-show="form.mode === 0" label="选择页面">
          <el-dropdown class="pageList-dropdown" trigger="hover" @visible-change="onVisibleChange">
            <div class="dropdown-toggle d-flex jc-between al-center bgc-white">
              <div class="d-flex">
                <span v-show="form.list.length === 0" class="t-light">请选择页面</span>
                <span v-show="form.list.length !== 0">已选{{ form.list.length }}个</span>
              </div>
              <i class="el-icon-arrow-down" :class="dropdownIn ? 'dropdown-in' : 't-light'"></i>
            </div>
            <el-dropdown-menu slot="dropdown" class="pageList-dropdown-menu">
              <el-checkbox-group v-model="form.list">
                <el-checkbox v-for="(page, i) in pageList" :key="i" :label="page">{{ page.name }}</el-checkbox>
              </el-checkbox-group>
            </el-dropdown-menu>
          </el-dropdown>
        </el-form-item>
      </el-form>
      <!-- 隐藏绘制-->
      <div v-if="loading" style="overflow: hidden; width: 0; height: 0">
        <Previewer
          v-for="page in form.list"
          :id="`tempPreviewer${page.id}`"
          :key="page.id"
          ref="previewer"
          :page-size="page.size"
          :page-style="page.style"
          :component-data="page.componentData"
        />
      </div>
    </div>
    <template #footer>
      <el-button @click="onClose">取消</el-button>
      <el-button type="primary" class="ml-24" :loading="loading" @click="onConfirm">确定</el-button>
    </template>
  </el-dialog>
</template>

<script>
  import html2canvas from 'html2canvas';
  import { saveAs } from 'file-saver';
  import JSZip from 'jszip';
  import Previewer from './Previewer';

  export default {
    components: { Previewer },
    props: {
      dialogType: { type: String, default: '' },
      appName: { type: String, default: '' },
      pageConfigList: { type: Array, default: () => [] },
      widgetConfigList: { type: Array, default: () => [] },
      canvasMode: { type: String, default: '' }
    },
    data() {
      return {
        form: {
          mimetype: 'image/jpeg',
          mode: 0,
          list: []
        },
        pageList: [],
        dropdownIn: false,
        loading: false,
        dialogShow: ''
      };
    },
    computed: {
      visible() {
        return this.dialogType === 'exportPageImages';
      }
    },
    provide() {
      return {
        onConfirm: this.onConfirm
      };
    },
    methods: {
      // 下拉多选
      onVisibleChange(visible) {
        this.dropdownIn = visible;
      },

      // 弹窗开启
      onOpen() {
        this.form = {
          mimetype: 'image/jpeg',
          mode: 0,
          list: []
        };
        this.pageList = this.pageConfigList.map((page, i) => ({
          id: page.id,
          name: page.name,
          $el: null,
          imageBlob: null,
          size: page.size,
          style: page.pageStyle,
          componentData: this.widgetConfigList[i]
        }));
      },
      

      // 打开进度弹窗
      // onDownload() {
      //   this.dialogShow = 'downloadProcess';
      // },

      // 确认生成
      onConfirm() {
        if (this.form.list.length === 0) {
          this.$message.error('请选择导出页面');
          return;
        }
        this.loading = true;
        this.$nextTick(() => {
          const $previewerList = this.$refs.previewer;
          this.form.list.forEach((page, i) => {
            page.$el = $previewerList[i].$el;
          });

          window.setTimeout(() => {
            const taskQueue = this.form.list.map((page) => this.generatePageImage(page));
            Promise.all(taskQueue)
              .then(() => this.downloadImagesFile())
              .then(() => {
                this.onClose();
                this.$message.success('导出图片成功');
              })
              .catch((err) => {
                console.warn(err);
                this.$message.error('导出图片失败');
              })
              .finally(() => {
                this.loading = false;
              });
          }, 200);
        });
      },

      onClose() {
        this.$emit('update:dialogType', '');
      },

      onChangeMode(mode) {
        if (mode === 0) this.form.list = [];
        if (mode === 1) this.form.list = this.pageList;
      },

      // 为page生成imageBlob
      generatePageImage(page) {
        const $page = page.$el;
        let $canvas = document.createElement('canvas');
        $canvas.width = $page.offsetWidth;
        $canvas.height = $page.offsetHeight;
        const options = {
          canvas: $canvas,
          useCORS: true,
          scale: 1,
          onclone: ($doc, $page_clone) => {
            // 内容canvas转为图片
            const canvasCollectionList = $page_clone.querySelectorAll('canvas');
            canvasCollectionList.forEach(($canvas) => {
              const $img = new Image();
              $img.style.width = $canvas.offsetWidth + 'px';
              $img.setAttribute('src', $canvas.toDataURL('image/png'));
              $canvas.parentNode.replaceChild($img, $canvas);
            });
          }
        };
        // ele => canvas => blob图片
        return html2canvas($page, options).then(
          ($ele) =>
            new Promise((resolve) => {
              if (this.form.mimetype === 'application/pdf') {
                const dataUrl = $ele.toDataURL('image/jpeg');
                page.imageBlob = dataUrl;
                resolve(dataUrl);
              } else {
                $ele.toBlob((Blob) => {
                  page.imageBlob = Blob;
                  resolve(Blob);
                  $canvas = null;
                }, this.form.mimetype);
              }
            })
        );
      },

      // 下载所有page.imagBlob为图片
      downloadImagesFile() {
        const mimetypeMap = new Map([
          ['image/jpeg', 'jpg'],
          ['image/png', 'png']
        ]);
        const fileExt = mimetypeMap.get(this.form.mimetype);
        // 单张图片直接下载
        if (this.form.list.length === 1) {
          const page = this.form.list[0];
          saveAs(page.imageBlob, `${page.name}.${fileExt}`);
          return;
        }
        // 多张图片zip下载
        const zip = new JSZip();
        this.form.list.forEach((page) => {
          if (page.imageBlob) zip.file(`${page.name}.${fileExt}`, page.imageBlob);
        });
        return zip.generateAsync({ type: 'blob' }).then((content) => {
          saveAs(content, `${this.appName}.zip`);
        });
      }
    }
  };
</script>

<style lang="scss" scoped>
  .dropdown-toggle {
    border: 1px solid #cecece;
    border-radius: 4px;
    padding: 0 16px;
    width: 360px;
    line-height: 32px;
    cursor: pointer;

    .el-icon-arrow-down {
      border-radius: 50%;
      padding: 2px;
      transition: all 0.3s;

      &.dropdown-in {
        transform: rotate(180deg);
      }
    }
  }

  .pageList-dropdown-menu {
    margin: 5px 0;
    padding: 8px 16px 8px 12px;
    width: 360px;

    ::v-deep {
      .el-checkbox-group {
        display: flex;
        flex-direction: column;

        .el-checkbox {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-right: 0;
          padding: 8px 0;

          .el-checkbox__input {
            order: 1;
          }

          .el-checkbox__label {
            order: 0;
            padding: 0;
          }
        }
      }
    }
  }

  ::v-deep {
    .el-radio__label {
      display: inline-flex;
      align-items: center;
    }
  }
</style>
